#include<iostream>
#include<queue>
#include<cstdlib>
#include<pthread.h>
#include<unistd.h>

#define MAX_QUEUE 5
template <class T>
class BlockQueue{
  private: 
    int _capacity;
    std::queue<T> _queue;
    pthread_mutex_t _mutex;
    pthread_cond_t _cond_pro;//生产者条件变量
    pthread_cond_t _cond_con;//消费者条件变量
  public:
    BlockQueue(int cap = MAX_QUEUE )//构造函数
      :_capacity(cap){
      pthread_mutex_init(&_mutex,NULL);
      pthread_cond_init(&_cond_con,NULL);
      pthread_cond_init(&_cond_pro,NULL);
    }

    ~BlockQueue(){
      pthread_mutex_destroy(&_mutex);//销毁互斥锁
      pthread_cond_destroy(&_cond_con);//销毁条件变量
      pthread_cond_destroy(&_cond_pro);//销毁条件变量
    }

    bool Push(const T &data){   //入队列
      pthread_mutex_lock(&_mutex);//先加锁
      while(_queue.size() == _capacity ){   //循环判断队列是否还有空间
        pthread_cond_wait(&_cond_pro,&_mutex);//阻塞生产者
      }
      _queue.push(data);
      pthread_mutex_unlock(&_mutex);
      pthread_cond_signal(&_cond_con);//唤醒消费者
    }
    
    bool Pop(T* data){
      pthread_mutex_lock(&_mutex);
      while(_queue.empty() == true){ //循环判断队列是否为空
        pthread_cond_wait(&_cond_con,&_mutex);
      }
      *data = _queue.front();//获取队头元素
      _queue.pop();
      pthread_mutex_unlock(&_mutex);
      pthread_cond_signal(&_cond_pro);//唤醒生产者
    }
};

typedef void (*handler_t)(int data);//这个函数指针指向无返回值的，一个形参是int的函数
class ThreadTask{   //定义一个结构体，里面包含 1.要处理的数据 2.处理方法
  private:
    int _data;
    handler_t _handler;
  public:
    ThreadTask(){} //默认的构造函数
    ThreadTask(int data, handler_t handler)
      :_data(data),_handler(handler){}

    void Run(){  // 通过_handler的地址访问函数
      _handler(_data);
      return ;
    }
};

#define MAX_THREAD 5
class ThreadPool{
  private:
    int thread_count;
    //pthread_t *tid;
    BlockQueue<ThreadTask> _queue;  //一个锁队列，类型是上面的结构体

  private:
      static void* worker(void *arg){  //必须要是静态的，不然还有一个this指针，这样不符合线程入口函数，形参个数为一的要求。
      ThreadPool *pool = (ThreadPool*)arg;//形参传this的值，这样就可以知道要访问的对象了
      while(1){
        ThreadTask task;
        pool->_queue.Pop(&task);//输出参数task，获取队头的元素
        task.Run();
      }
      return NULL;
    }

  public:
    ThreadPool(int tcount = MAX_THREAD, int qcount = MAX_QUEUE)
      :thread_count(tcount),_queue(qcount){//默认构造函数直接在创建对象时，创建tcount个数的线程，准备干活
        int ret;
        pthread_t tid;
        for(int i = 0; i < tcount; i++){
          ret = pthread_create(&tid,NULL,worker,this);//创建线程
          if(ret != 0){
            printf("create thread error!\n");
            exit(0);
          }
          pthread_detach(tid);//分离线程，其退出的时候，自动释放资源
        }
      }

    bool Push(const ThreadTask & task){ //往线程池放数据，就是往它的队列里存放数据
      _queue.Push(task);
    } 
};
void test(int data)//处理方法
{
  printf("thread:%p-data:%d-sleep %d sec\n",pthread_self(),data,data);
  sleep(data);
}

int main()
{
  ThreadPool pool;
  for(int i = 0; i < 10 ; i++){ //循环创建task，要处理的数据从0到9，之后入线程池.
    ThreadTask task(i,test);
    pool.Push(task);
  }
  while(1) sleep(1);
  return 0;
}
